home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet multimedia / Muzyka / Edytory sampli (probek dzwieku) / ZynAddSubFX_2.2.0 / Setup_ZynAddSubFX-2.2.0.exe / source code / Misc / Microtonal.C < prev    next >
C/C++ Source or Header  |  2005-03-14  |  15KB  |  515 lines

  1. /*
  2.   ZynAddSubFX - a software synthesizer
  3.  
  4.   Microtonal.C - Tuning settings and microtonal capabilities
  5.   Copyright (C) 2002-2005 Nasca Octavian Paul
  6.   Author: Nasca Octavian Paul
  7.  
  8.   This program is free software; you can redistribute it and/or modify
  9.   it under the terms of version 2 of the GNU General Public License 
  10.   as published by the Free Software Foundation.
  11.  
  12.   This program is distributed in the hope that it will be useful,
  13.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.   GNU General Public License (version 2) for more details.
  16.  
  17.   You should have received a copy of the GNU General Public License (version 2)
  18.   along with this program; if not, write to the Free Software Foundation,
  19.   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  20.  
  21. */
  22.  
  23. #include <math.h>
  24. #include <string.h>
  25. #include "Microtonal.h"
  26.  
  27. #define MAX_LINE_SIZE 80
  28.  
  29. Microtonal::Microtonal(){
  30.     Pname=new unsigned char[MICROTONAL_MAX_NAME_LEN];
  31.     Pcomment=new unsigned char[MICROTONAL_MAX_NAME_LEN];
  32.     defaults();
  33. };
  34.  
  35. void Microtonal::defaults(){
  36.     Pinvertupdown=0;
  37.     Pinvertupdowncenter=60;
  38.     octavesize=12;
  39.     Penabled=0;
  40.     PAnote=69;
  41.     PAfreq=440.0;
  42.     Pscaleshift=64;
  43.     
  44.     Pfirstkey=0;Plastkey=127;
  45.     Pmiddlenote=60;Pmapsize=12;
  46.     Pmappingenabled=0;
  47.     
  48.     for (int i=0;i<128;i++) Pmapping[i]=i;
  49.     
  50.     for (int i=0;i<MAX_OCTAVE_SIZE;i++){
  51.     octave[i].tuning=tmpoctave[i].tuning=pow(2,(i%octavesize+1)/12.0);
  52.     octave[i].type=tmpoctave[i].type=1;
  53.     octave[i].x1=tmpoctave[i].x1=(i%octavesize+1)*100;
  54.     octave[i].x2=tmpoctave[i].x2=0;
  55.     };
  56.     octave[11].type=2;octave[11].x1=2;octave[11].x2=1;
  57.     for (int i=0;i<MICROTONAL_MAX_NAME_LEN;i++){
  58.     Pname[i]='\0';
  59.     Pcomment[i]='\0';
  60.     };
  61.     snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"12tET");
  62.     snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"Equal Temperament 12 notes per octave");    
  63.     Pglobalfinedetune=64;
  64. };
  65.  
  66. Microtonal::~Microtonal(){
  67.     delete (Pname);
  68.     delete (Pcomment);
  69. };
  70.  
  71. /*
  72.  * Get the size of the octave
  73.  */
  74. unsigned char Microtonal::getoctavesize(){
  75.     if (Penabled!=0) return(octavesize);
  76.     else return(12);
  77. };
  78.  
  79. /*
  80.  * Get the frequency according the note number
  81.  */
  82. REALTYPE Microtonal::getnotefreq(int note,int keyshift){
  83.     // in this function will appears many times things like this:
  84.     // var=(a+b*100)%b 
  85.     // I had written this way because if I use var=a%b gives unwanted results when a<0
  86.     // This is the same with divisions.
  87.     
  88.     if ((Pinvertupdown!=0)&&((Pmappingenabled==0)||(Penabled==0))) note=(int) Pinvertupdowncenter*2-note;
  89.  
  90.     //compute global fine detune
  91.     REALTYPE globalfinedetunerap=pow(2.0,(Pglobalfinedetune-64.0)/1200.0);//-64.0 .. 63.0 cents
  92.         
  93.     if (Penabled==0) return(pow(2.0,(note-PAnote+keyshift)/12.0)*PAfreq*globalfinedetunerap);//12tET
  94.     
  95.     int scaleshift=((int)Pscaleshift-64+(int) octavesize*100)%octavesize;
  96.  
  97.     //compute the keyshift
  98.     REALTYPE rap_keyshift=1.0;
  99.     if (keyshift!=0){
  100.     int kskey=(keyshift+(int)octavesize*100)%octavesize;
  101.     int ksoct=(keyshift+(int)octavesize*100)/octavesize-100;
  102.     rap_keyshift=(kskey==0) ? (1.0):(octave[kskey-1].tuning);
  103.     rap_keyshift*=pow(octave[octavesize-1].tuning,ksoct);
  104.     };
  105.  
  106.     //if the mapping is enabled
  107.     if (Pmappingenabled!=0){
  108.     if ((note<Pfirstkey)||(note>Plastkey)) return (-1.0);
  109.     //Compute how many mapped keys are from middle note to reference note
  110.     //and find out the proportion between the freq. of middle note and "A" note
  111.     int tmp=PAnote-Pmiddlenote,minus=0;
  112.     if (tmp<0) { tmp=-tmp; minus=1; };
  113.     int deltanote=0;
  114.     for (int i=0;i<tmp;i++) if (Pmapping[i%Pmapsize]>=0) deltanote++;
  115.     REALTYPE rap_anote_middlenote=(deltanote==0) ? (1.0) : (octave[(deltanote-1)%octavesize].tuning);
  116.     if (deltanote!=0) rap_anote_middlenote*=pow(octave[octavesize-1].tuning,(deltanote-1)/octavesize);
  117.     if (minus!=0) rap_anote_middlenote=1.0/rap_anote_middlenote;
  118.     
  119.     //Convert from note (midi) to degree (note from the tunning)
  120.     int degoct=(note-(int)Pmiddlenote+(int) Pmapsize*200)/(int)Pmapsize-200;
  121.     int degkey=(note-Pmiddlenote+(int)Pmapsize*100)%Pmapsize;
  122.     degkey=Pmapping[degkey];
  123.     if (degkey<0) return(-1.0);//this key is not mapped
  124.     
  125.     //invert the keyboard upside-down if it is asked for
  126.     //TODO: do the right way by using Pinvertupdowncenter
  127.     if (Pinvertupdown!=0){
  128.         degkey=octavesize-degkey-1;
  129.         degoct=-degoct;
  130.     };
  131.     //compute the frequency of the note
  132.     degkey=degkey+scaleshift;
  133.     degoct+=degkey/octavesize;
  134.     degkey%=octavesize;
  135.  
  136.     REALTYPE freq=(degkey==0) ? (1.0):octave[degkey-1].tuning;
  137.     freq*=pow(octave[octavesize-1].tuning,degoct);
  138.     freq*=PAfreq/rap_anote_middlenote;
  139.     freq*=globalfinedetunerap;
  140.     if (scaleshift!=0) freq/=octave[scaleshift-1].tuning;
  141.     return(freq*rap_keyshift);
  142.     } else {//if the mapping is disabled
  143.     int nt=note-PAnote+scaleshift;
  144.     int ntkey=(nt+(int)octavesize*100)%octavesize;
  145.     int ntoct=(nt-ntkey)/octavesize;    
  146.     
  147.     REALTYPE oct=octave[octavesize-1].tuning;
  148.     REALTYPE freq=octave[(ntkey+octavesize-1)%octavesize].tuning*pow(oct,ntoct)*PAfreq;
  149.     if (ntkey==0) freq/=oct;
  150.         if (scaleshift!=0) freq/=octave[scaleshift-1].tuning;
  151. //    fprintf(stderr,"note=%d freq=%.3f cents=%d\n",note,freq,(int)floor(log(freq/PAfreq)/log(2.0)*1200.0+0.5));
  152.     freq*=globalfinedetunerap;
  153.         return(freq*rap_keyshift);
  154.     };
  155. };
  156.  
  157.  
  158. /*
  159.  * Convert a line to tunings; returns -1 if it ok
  160.  */
  161. int Microtonal::linetotunings(unsigned int nline,const char *line){
  162.     int x1=-1,x2=-1,type=-1;
  163.     REALTYPE x=-1.0,tmp,tuning=1.0;
  164.     if (strstr(line,"/")==NULL){
  165.     if (strstr(line,".")==NULL){// M case (M=M/1)
  166.         sscanf(line,"%d",&x1);
  167.         x2=1;
  168.         type=2;//division
  169.     } else {// float number case
  170.             sscanf(line,"%f",&x);
  171.         if (x<0.000001) return(1);
  172.         type=1;//float type(cents)
  173.     };
  174.     } else {// M/N case
  175.     sscanf(line,"%d/%d",&x1,&x2);
  176.     if ((x1<0)||(x2<0)) return(1);
  177.     if (x2==0) x2=1;
  178.     type=2;//division
  179.     };
  180.     
  181.     if (x1<=0) x1=1;//not allow zero frequency sounds (consider 0 as 1)
  182.     
  183.     //convert to float if the number are too big
  184.     if ((type==2)&&((x1>(128*128*128-1))||(x2>(128*128*128-1)))){
  185.     type=1;
  186.     x=((REALTYPE) x1)/x2;
  187.     };
  188.     switch (type){
  189.     case 1:    x1=(int) floor(x);
  190.         tmp=fmod(x,1.0);
  191.         x2=(int) (floor (tmp*1e6));
  192.         tuning=pow(2.0,x/1200.0);
  193.         break;
  194.     case 2:    x=((REALTYPE)x1)/x2;
  195.         tuning=x;
  196.         break;
  197.     };
  198.     
  199.     tmpoctave[nline].tuning=tuning;
  200.     tmpoctave[nline].type=type;
  201.     tmpoctave[nline].x1=x1;
  202.     tmpoctave[nline].x2=x2;
  203.     
  204.     return(-1);//ok
  205. };
  206.  
  207. /*
  208.  * Convert the text to tunnings
  209.  */
  210. int Microtonal::texttotunings(const char *text){
  211.     unsigned int i,k=0,nl=0;
  212.     char *lin;
  213.     lin=new char[MAX_LINE_SIZE+1];
  214.     while (k<strlen(text)){
  215.     for (i=0;i<MAX_LINE_SIZE;i++){
  216.         lin[i]=text[k++];
  217.         if (lin[i]<0x20) break;
  218.     };
  219.     lin[i]='\0';
  220.     if (strlen(lin)==0) continue;
  221.     int err=linetotunings(nl,lin);
  222.     if (err!=-1) {
  223.         delete [] lin;
  224.         return(nl);//Parse error
  225.     };
  226.     nl++;
  227.     };
  228.     delete [] lin;
  229.     if (nl>MAX_OCTAVE_SIZE) nl=MAX_OCTAVE_SIZE;
  230.     if (nl==0) return(-2);//the input is empty
  231.     octavesize=nl;
  232.     for (i=0;i<octavesize;i++){
  233.     octave[i].tuning=tmpoctave[i].tuning;
  234.     octave[i].type=tmpoctave[i].type;
  235.     octave[i].x1=tmpoctave[i].x1;
  236.     octave[i].x2=tmpoctave[i].x2;
  237.     };
  238.     return(-1);//ok
  239. };
  240.  
  241. /*
  242.  * Convert the text to mapping
  243.  */
  244. void Microtonal::texttomapping(const char *text){
  245.     unsigned int i,k=0;
  246.     char *lin;
  247.     lin=new char[MAX_LINE_SIZE+1];
  248.     for (i=0;i<128;i++) Pmapping[i]=-1;
  249.     int tx=0;
  250.     while (k<strlen(text)){
  251.     for (i=0;i<MAX_LINE_SIZE;i++){
  252.         lin[i]=text[k++];
  253.         if (lin[i]<0x20) break;
  254.     };
  255.     lin[i]='\0';
  256.     if (strlen(lin)==0) continue;
  257.  
  258.     int tmp=0;
  259.     if (sscanf(lin,"%d",&tmp)==0) tmp=-1;
  260.     if (tmp<-1) tmp=-1;
  261.     Pmapping[tx]=tmp;
  262.     
  263.     if ((tx++)>127) break;
  264.     };
  265.     delete [] lin;
  266.     
  267.     if (tx==0) tx=1;
  268.     Pmapsize=tx;
  269. };
  270.  
  271. /*
  272.  * Convert tunning to text line
  273.  */
  274. void Microtonal::tuningtoline(int n,char *line,int maxn){
  275.     if ((n>octavesize) || (n>MAX_OCTAVE_SIZE)) {
  276.     line[0]='\0';
  277.     return;
  278.     };
  279.     if (octave[n].type==1) snprintf(line,maxn,"%d.%d",octave[n].x1,octave[n].x2);
  280.     if (octave[n].type==2) snprintf(line,maxn,"%d/%d",octave[n].x1,octave[n].x2);
  281. };
  282.  
  283.  
  284. int Microtonal::loadline(FILE *file,char *line){
  285.     do {
  286.     if (fgets(line,500,file)==0) return(1);
  287.     } while (line[0]=='!');
  288.     return(0);
  289. };
  290. /*
  291.  * Loads the tunnings from a scl file
  292.  */
  293. int Microtonal::loadscl(const char *filename){
  294.     FILE *file=fopen(filename, "r");
  295.     char tmp[500];
  296.     fseek(file,0,SEEK_SET);
  297.     //loads the short description
  298.     if (loadline(file,&tmp[0])!=0) return(2);
  299.     for (int i=0;i<500;i++) if (tmp[i]<32) tmp[i]=0;
  300.     snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"%s",tmp);
  301.     snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"%s",tmp);
  302.     //loads the number of the notes
  303.     if (loadline(file,&tmp[0])!=0) return(2);
  304.     int nnotes=MAX_OCTAVE_SIZE;
  305.     sscanf(&tmp[0],"%d",&nnotes);
  306.     if (nnotes>MAX_OCTAVE_SIZE) return (2);
  307.     //load the tunnings
  308.     for (int nline=0;nline<nnotes;nline++){
  309.     if (loadline(file,&tmp[0])!=0) return(2);
  310.     linetotunings(nline,&tmp[0]);
  311.     };
  312.     fclose(file);
  313.  
  314.     octavesize=nnotes;
  315.     for (int i=0;i<octavesize;i++){
  316.     octave[i].tuning=tmpoctave[i].tuning;
  317.     octave[i].type=tmpoctave[i].type;
  318.     octave[i].x1=tmpoctave[i].x1;
  319.     octave[i].x2=tmpoctave[i].x2;
  320.     };
  321.  
  322.     return(0);
  323. };
  324.  
  325. /*
  326.  * Loads the mapping from a kbm file
  327.  */
  328. int Microtonal::loadkbm(const char *filename){
  329.     FILE *file=fopen(filename, "r");
  330.     int x;
  331.     char tmp[500];
  332.  
  333.     fseek(file,0,SEEK_SET);
  334.     //loads the mapsize
  335.     if (loadline(file,&tmp[0])!=0) return(2);
  336.     if (sscanf(&tmp[0],"%d",&x)==0) return(2);
  337.     if (x<1) x=0;if (x>127) x=127;//just in case...
  338.     Pmapsize=x;
  339.     //loads first MIDI note to retune
  340.     if (loadline(file,&tmp[0])!=0) return(2);
  341.     if (sscanf(&tmp[0],"%d",&x)==0) return(2);
  342.     if (x<1) x=0;if (x>127) x=127;//just in case...
  343.     Pfirstkey=x;
  344.     //loads last MIDI note to retune
  345.     if (loadline(file,&tmp[0])!=0) return(2);
  346.     if (sscanf(&tmp[0],"%d",&x)==0) return(2);
  347.     if (x<1) x=0;if (x>127) x=127;//just in case...
  348.     Plastkey=x;
  349.     //loads last the middle note where scale fro scale degree=0
  350.     if (loadline(file,&tmp[0])!=0) return(2);
  351.     if (sscanf(&tmp[0],"%d",&x)==0) return(2);
  352.     if (x<1) x=0;if (x>127) x=127;//just in case...
  353.     Pmiddlenote=x;
  354.     //loads the reference note
  355.     if (loadline(file,&tmp[0])!=0) return(2);
  356.     if (sscanf(&tmp[0],"%d",&x)==0) return(2);
  357.     if (x<1) x=0;if (x>127) x=127;//just in case...
  358.     PAnote=x;
  359.     //loads the reference freq.
  360.     if (loadline(file,&tmp[0])!=0) return(2);
  361.     REALTYPE tmpPAfreq=440.0;
  362.     if (sscanf(&tmp[0],"%f",&tmpPAfreq)==0) return(2);
  363.     PAfreq=tmpPAfreq;
  364.  
  365.     //the scale degree(which is the octave) is not loaded, it is obtained by the tunnings with getoctavesize() method
  366.     if (loadline(file,&tmp[0])!=0) return(2);
  367.  
  368.     //load the mappings
  369.     if (Pmapsize!=0){
  370.     for (int nline=0;nline<Pmapsize;nline++){
  371.         if (loadline(file,&tmp[0])!=0) return(2);
  372.         if (sscanf(&tmp[0],"%d",&x)==0) x=-1;
  373.         Pmapping[nline]=x;
  374.     };
  375.     Pmappingenabled=1;
  376.     } else {
  377.     Pmappingenabled=0;
  378.     Pmapping[0]=0;
  379.     Pmapsize=1;
  380.     };
  381.     fclose(file);
  382.  
  383.     return(0);
  384. };
  385.  
  386.  
  387.  
  388. void Microtonal::add2XML(XMLwrapper *xml){
  389.     xml->addparstr("name",(char *) Pname);
  390.     xml->addparstr("comment",(char *) Pcomment);
  391.  
  392.     xml->addparbool("invert_up_down",Pinvertupdown);
  393.     xml->addparbool("invert_up_down_center",Pinvertupdowncenter);
  394.  
  395.     xml->addparbool("enabled",Penabled);
  396.     xml->addpar("global_fine_detune",Pglobalfinedetune);
  397.  
  398.     xml->addpar("a_note",PAnote);
  399.     xml->addparreal("a_freq",PAfreq);
  400.  
  401.     if ((Penabled==0)&&(xml->minimal)) return;
  402.  
  403.     xml->beginbranch("SCALE");
  404.         xml->addpar("scale_shift",Pscaleshift);
  405.     xml->addpar("first_key",Pfirstkey);
  406.     xml->addpar("last_key",Plastkey);
  407.     xml->addpar("middle_note",Pmiddlenote);
  408.  
  409.     xml->beginbranch("OCTAVE");
  410.         xml->addpar("octave_size",octavesize);
  411.         for (int i=0;i<octavesize;i++){
  412.         xml->beginbranch("DEGREE",i);
  413.             if (octave[i].type==1){            
  414.             xml->addparreal("cents",octave[i].tuning);
  415.             };
  416.             if (octave[i].type==2){            
  417.             xml->addpar("numerator",octave[i].x1);
  418.             xml->addpar("denominator",octave[i].x2);
  419.             };
  420.         xml->endbranch();
  421.         };
  422.     xml->endbranch();
  423.  
  424.     xml->beginbranch("KEYBOARD_MAPPING");
  425.         xml->addpar("map_size",Pmapsize);
  426.         xml->addpar("mapping_enabled",Pmappingenabled);
  427.         for (int i=0;i<Pmapsize;i++){
  428.             xml->beginbranch("KEYMAP",i);
  429.             xml->addpar("degree",Pmapping[i]);
  430.             xml->endbranch();
  431.         };
  432.     xml->endbranch();
  433.     xml->endbranch();
  434. };
  435.  
  436. void Microtonal::getfromXML(XMLwrapper *xml){
  437.     xml->getparstr("name",(char *) Pname,MICROTONAL_MAX_NAME_LEN);
  438.     xml->getparstr("comment",(char *) Pcomment,MICROTONAL_MAX_NAME_LEN);
  439.  
  440.     Pinvertupdown=xml->getparbool("invert_up_down",Pinvertupdown);
  441.     Pinvertupdowncenter=xml->getparbool("invert_up_down_center",Pinvertupdowncenter);
  442.  
  443.     Penabled=xml->getparbool("enabled",Penabled);
  444.     Pglobalfinedetune=xml->getpar127("global_fine_detune",Pglobalfinedetune);
  445.  
  446.     PAnote=xml->getpar127("a_note",PAnote);
  447.     PAfreq=xml->getparreal("a_freq",PAfreq,1.0,10000.0);
  448.  
  449.     if (xml->enterbranch("SCALE")){
  450.     Pscaleshift=xml->getpar127("scale_shift",Pscaleshift);
  451.     Pfirstkey=xml->getpar127("first_key",Pfirstkey);
  452.     Plastkey=xml->getpar127("last_key",Plastkey);
  453.     Pmiddlenote=xml->getpar127("middle_note",Pmiddlenote);
  454.  
  455.     if (xml->enterbranch("OCTAVE")){
  456.         octavesize=xml->getpar127("octave_size",octavesize);
  457.         for (int i=0;i<octavesize;i++){
  458.         if (xml->enterbranch("DEGREE",i)==0) continue;
  459.             octave[i].x2=0;
  460.             octave[i].tuning=xml->getparreal("cents",octave[i].tuning);
  461.             octave[i].x1=xml->getpar127("numerator",octave[i].x1);
  462.             octave[i].x2=xml->getpar127("denominator",octave[i].x2);
  463.             
  464.             if (octave[i].x2!=0) octave[i].type=2; 
  465.             else octave[i].type=1;
  466.             
  467.         xml->exitbranch();
  468.         };
  469.         xml->exitbranch();
  470.     };
  471.  
  472.     if (xml->enterbranch("KEYBOARD_MAPPING")){
  473.         Pmapsize=xml->getpar127("map_size",Pmapsize);
  474.         Pmappingenabled=xml->getpar127("mapping_enabled",Pmappingenabled);
  475.         for (int i=0;i<Pmapsize;i++){
  476.             if (xml->enterbranch("KEYMAP",i)==0) continue;
  477.             Pmapping[i]=xml->getpar127("degree",Pmapping[i]);
  478.             xml->exitbranch();
  479.         };
  480.         xml->exitbranch();
  481.     };
  482.     xml->exitbranch();
  483.     };
  484. };
  485.  
  486.  
  487. int Microtonal::saveXML(char *filename){
  488.     XMLwrapper *xml=new XMLwrapper();
  489.  
  490.     xml->beginbranch("MICROTONAL");
  491.     add2XML(xml);
  492.     xml->endbranch();
  493.  
  494.     int result=xml->saveXMLfile(filename);
  495.     delete (xml);
  496.     return(result);
  497. };
  498.  
  499. int Microtonal::loadXML(char *filename){
  500.     XMLwrapper *xml=new XMLwrapper();
  501.     if (xml->loadXMLfile(filename)<0) {
  502.     delete(xml);
  503.     return(-1);
  504.     };
  505.     
  506.     if (xml->enterbranch("MICROTONAL")==0) return(-10);
  507.     getfromXML(xml);
  508.     xml->exitbranch();
  509.     
  510.     delete(xml);
  511.     return(0);
  512. };
  513.  
  514.  
  515.